Android SystemUI 分析——状态栏图标
更新日期:
通知篇说了一下有关 Notification 相关的东西,其中 Notification 有一个 UI 表现就是状态栏的图标,不过这篇说的是另外一种东西,虽然 UI 表现上和 Notification 的状态栏图标一样,但是使用上是不一样的。还是先照例把相关代码位置啰嗦一下(4.2.2):
|
|
区分
我们先来看一张图:
图中状态栏左边那一堆图标是通知篇说的 Notification 的小图标,右边那一堆就是这篇要说的系统状态图标。虽然这篇的名字是状态栏图标,但是因为通知篇说过 Notification 的了,所以这里只说系统的状态图标。通知的图标是每一个通知一个,然后如果通知太多的话,后面会显示一个 “+” 的图标代表有更多的通知图标,所以说左边通知的图标是不确定的,是由运行不同的程序来决定的。而系统状态图标是固定的,在 framework 中代码写死一共有多少种系统状态,然后系统运行不同功能的时候显示某个状态的图标,完成后,图标消失。例如说,设置(关闭)闹钟、开启(关闭)飞行模式、开启(关闭)静音。这里稍微注意下,只有图上右边框出来的部分(只是一小部分而已)才是系统状态,wifi、电量信息和时间不属于系统状态图标的。
接口
我们先来看系统状态图标的接口,接口依旧在 StatusBarManager(SBM) 中:
|
|
对外接口很简单就3个:
- setIcon: 设置一个状态图标,主要参数是图标
- setIconVisibility: 设置一个状态图标显示(隐藏)
- removeIcon: 移除一个状态图标
值得一提的是,这些接口都是系统内部使用的,因为整个 SBM 都是 hide 的(aidl、java 都是)。应用只能通过一些别的方法间接的去改变系统状态图标,无法直接更改。例如要让系统状态显示设置了闹钟,就要发送 android.intent.action.ALARM_CHANGED 广播(SystemUI 中有接收这个广播的地方,然后调用上面的接口来改变系统状态图标显示)。
这个设计还是必须的,因为如果随便开放接口给第三方应用直接改系统状态显示,有些捣乱的应用就要乱来了。不过虽然是 hide 的,java 有反射可以干坏事,不过下面会说到,接口里面权限检测的,所以反射也干不了坏事。
固定的数据
看完上面接口,是不是觉得 setIcon 为什么不叫 addIcon,来看下系统的实现(设计)就明白了。我们直接去 StatusBarManagerService(SBMS)里去看,不看 Bp 端的:
|
|
最开始有前面说的权限检测:
|
|
检测下调用者是否有权限调用 SBMS,估计应该是要 system app 才行吧。然后有一个叫 StatusBarIconList mIcons 的数据结构:
|
|
名字也很形象,内部是用一个数组封装了下 StatusBarIcon,然后以 String 为标志(我觉得内部用 HashMap
然后这个数组是在 SBMS 构造函数那里初始化的:
|
|
xml 中的数组在这:
|
|
4.2 的原生系统有上面 19 个系统状态图标。我们接下来把剩下2个接口也看完:
|
|
SystemUI 的处理
上面 SBMS 虽然有3个接口,但是 UI 这边就只有2个:
|
|
上面 SBMS 的实现也看到了,也只是用到 UI 这边2个接口。前面通知篇分析了 SystemUI 状态栏的一些设计和 UI 和 SS 那些关系的,这里就省略了(忘了的回去看一下)。桥接依旧在 CommandQueue:
|
|
经过桥接的 CommandQueue 最后交给 UI 实现的接口又变成3个了:
|
|
然后 UI 这边又有一个 StatusBarIconList 的 mList,最后这个 list 是在这的:
|
|
比起通知,系统状态数据只存了2份(SBMS,SystemUI),还算好的了(通知存了3份: NM,SBMS,SystemUI)。然后从上面的代码来看,3个接口主要是:
- addIcon: 如果调用的 setIcon 的 slot 没有在 SystemUI 中的数据有记录,那么会调用这个,让 SystemUI 添加一个新的状态图标(StatusBarIconView)
- updateIcon: 如果调用的 setIcon 的 slot 在 SystemUI 中有记录,那么会调用这个,让 SystemUI 更新下已有的状态图标状态
- removeIcon: 让 SystemUI 移除一个已经添加的状态图标
我们以 PhoneStatusBar 为例,来看下相关的实现:
|
|
实现都比较简单,然后去 StatusBarIconView 里面看看更新状态的:
|
|
通过上面可以看到前面 SBMS 的 setIconVisibility 改变 StatusBarIcon 的 visible 属性,最后到 UI 这就是变成改变状态图标的 view 的 VISIBLE(GONE)属性。
然后前面说 4.2 系统的状态图标数组有 19 个,一般状态栏应该是放不下的。其实不用担心,因为虽然数据数组有 19 个,但是只是 NULL 的占位而已。要调用 SBMS 的 setIcon 才会正在填充数据进去,进而通知 UI 添加状态图标 view 到 WindowManager(WM)中(显示在界面上)。dumpsys 一下 SBMS 会发现 4.2 默认系统的状态图标有下面几个:
|
|
19 个列表中有很多是空的(null)的,要让系统显示那些状态,需要调用 SBMS 的 setIcon 设置才会填充图标数据。4.2 中主要在 SystemUI 的 PhoneStatusBarPolicy 中设置的(以 Phone UI 为例子):
|
|
然后稍微贴一下 PhoneStatusBarPolicy 中更新这些状态的代码:
|
|
还有一个输入法的在这里(InputMethodManagerService.java):
|
|
总结
这篇内容比较简单。系统状态图标数据和通知的状态栏图标是一样的,都是 StautsBarIcon,视图也是一样的(StatusBarIconView),因为它们 UI 表现是一样的。只不过一个是显示应用的信息,一个是显示系统的状态信息;一个可以动态改变数量,一个固定数量而已。不过还是这2种不同系统 UI 元素还是要区分一些,不然有些时候搞混了,就找不到在哪定制这些东西了。